package org.hilo.boot.core.redis;

import org.hilo.boot.core.UT;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 
 * @author zollty
 * @since 2018年6月26日
 */
public class RedisTemplateConfiguration {

    // JedisConnectionFactory
    protected RedisConnectionFactory connectionFactory;
    
    public RedisTemplateConfiguration(RedisConnectionFactory connectionFactory) {
        this.connectionFactory = connectionFactory;
    }
    
    
    // ~~ helper method

    /**
     * Serialize hashkey and value to JSON String using the 
     * org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer
     * @see Jackson2JsonRedisSerializer
     */
    public <HK, HV> RedisTemplate<String, HV> initRedisTemplate(Class<HK> keyClass, Class<HV> valClass) {
        RedisTemplate<String, HV> redisTemplate = new RedisTemplate<String, HV>();
        redisTemplate.setConnectionFactory(connectionFactory);

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);

        ObjectMapper objectMapper = UT.Json.getObjectMapperNoTransform();
        redisTemplate.setValueSerializer(redisSerializer(objectMapper, valClass));
        redisTemplate.setHashValueSerializer(redisSerializer(objectMapper, valClass));

        redisTemplate.setHashKeySerializer(redisSerializer(objectMapper, keyClass));

        // 自己new出来的RedisTemplate，需要手动调用下面方法
        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }

    /**
     * Serialize key and value to String using the 
     * org.springframework.data.redis.serializer.GenericToStringSerializer
     * @see GenericToStringSerializer
     * @see org.springframework.core.convert.support.DefaultConversionService
     */
    public <T> RedisTemplate<String, T> initGenericToStrTemplate(Class<T> clazz) {
        RedisTemplate<String, T> redisTemplate = new RedisTemplate<String, T>();
        redisTemplate.setConnectionFactory(connectionFactory);
        
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        RedisSerializer<?> redisSerializer = new GenericToStringSerializer<T>(clazz);
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(redisSerializer);
        redisTemplate.setHashValueSerializer(redisSerializer);
        
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /** key序列化用StringRedisSerializer，value值使用默认的序列化方式（JDK Serial） */
    public <T> RedisTemplate<String, T> initJdkSerialTemplate(Class<T> clazz) {
        RedisTemplate<String, T> redisTemplate = new RedisTemplate<String, T>();
        redisTemplate.setConnectionFactory(connectionFactory);
        
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
    
    private <T> RedisSerializer<?> redisSerializer(ObjectMapper objectMapper, Class<T> clazz) {
        if (clazz == String.class) {
            return new StringRedisSerializer();
        }
        Jackson2JsonRedisSerializer<T> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<T>(clazz);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        return jackson2JsonRedisSerializer;
    }
}
